package com.xyy.saas.payment.settle.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.xyy.saas.payment.adpater.RouteManager;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.bo.SubAppBo;
import com.xyy.saas.payment.cores.bo.UserBo;
import com.xyy.saas.payment.cores.bo.UserPicBo;
import com.xyy.saas.payment.cores.enums.*;
import com.xyy.saas.payment.cores.vo.ResultVO;
import com.xyy.saas.payment.dao.model.*;
import com.xyy.saas.payment.merchant.core.dto.*;
import com.xyy.saas.payment.merchant.core.service.ApplyBankcardService;
import com.xyy.saas.payment.merchant.core.vo.AccountDto;
import com.xyy.saas.payment.merchant.core.vo.*;
import com.xyy.saas.payment.payment.core.dto.ActiveCodeDto;
import com.xyy.saas.payment.service.*;
import com.xyy.saas.payment.settle.core.service.AccountService;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.JSONUtils;
import com.xyy.saas.payment.util.LeafUtil;
import com.xyy.saas.payment.util.MatcherUtil;
import com.xyy.util.StringUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import util.AESUtil;

import javax.annotation.Resource;
import java.util.*;

/**
 * @Date: 2019/10/22 17:58
 */
@DependsOn("apolloUtil")
@Service
public class AccountServiceImpl implements AccountService {
    private static Logger LOGGER = LoggerFactory.getLogger(AccountServiceImpl.class);
    @Autowired
    private PayAccountService payAccountService;
    @Autowired
    private LeafUtil leafUtil;
    @Autowired
    private RouteManager routeManager;
    @Autowired
    private ThirdUserInfoService thirdUserInfoService;
    @Autowired
    private FmBankCodeService fmBankCodeService;
    @Autowired
    private SubBankCodeService subBankCodeService;
    @Autowired
    UserInfoService userInfoService;
    @Resource
    private ApplyBankcardService applyBankcardService;

    private static String wareJson = ApolloUtil.getProperty(Constants.WARE_ENCRYPTION);

    private static String fileUploadUrl = "https://saas-yzh.ybm100.com/api/fileoper/uploadFile";

    private static Map<String, String> wareMap;
    public static List<String> picFormat = new ArrayList<>();
    static {
        picFormat.add("png");
        picFormat.add("jpg");
        wareMap = JSONUtils.parse2Map(wareJson, String.class, String.class);
    }
    @Override
    public ResultVO createAccount(AccountDto accountDto){
        ResultVO resultVO = new ResultVO();
        if (!isValidUploadParam(accountDto)){
            LOGGER.warn("AccountServiceImpl createAccount param error accountDto:{}", JSON.toJSON(accountDto));
            return ResultVO.createParamError();
        }

        // 先查询是否已经生成,如果生成返回accountId
        String accountId = payAccountService.getAccountIdByBusiness(accountDto.getBusinessIdType(), accountDto.getBusinessUserId());
        if (accountId != null){
            LOGGER.warn("AccountServiceImpl createAccount account is exist accountId:{}", accountId);
            resultVO.setCode(ResultCodeEnum.ACCOUNT_IS_EXIST.getCode());
            resultVO.setMsg(ResultCodeEnum.ACCOUNT_IS_EXIST.getMsg());
            resultVO.setResult(accountId);
            return resultVO;
        }

        PayAccount payAccount = new PayAccount();
        accountId = Long.toHexString(Long.parseLong(leafUtil.getSegmentId("user")));
        if (accountId == null){
            LOGGER.warn("AccountServiceImpl createAccount get userId error userDto:{}, idType:{}", JSON.toJSON(accountDto), accountDto.getBusinessIdType());
            resultVO.setCode(ResultCodeEnum.GET_USER_ID_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.GET_USER_ID_ERROR.getMsg());
            return resultVO;
        }
        payAccount.setAccountId(accountId);
        payAccount.setBusinessIdType(accountDto.getBusinessIdType());
        payAccount.setBusinessUserId(accountDto.getBusinessUserId());
        payAccount.setCtime(new Date());
        int count = payAccountService.createAccount(payAccount);
        if (count<1){
            LOGGER.error("AccountServiceImpl uploadPic createUser error payAccount:{}", payAccount);
            resultVO.setCode(ResultCodeEnum.PARAM_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.PARAM_ERROR.getMsg());
            return resultVO;
        }
        resultVO.setCode(ResultCodeEnum.SUCCESS.getCode());
        resultVO.setMsg(ResultCodeEnum.SUCCESS.getMsg());
        resultVO.setResult(JSONUtils.toJSON(payAccount));
        return resultVO;
    }

    @Override
    public ResultVO<String> createCPEAccount(AccountDto accountDto) throws Exception {
        ResultVO resultVO = createAccount(accountDto);
        String accountId = null;
        if(!resultVO.getCode().equals(ResultCodeEnum.SUCCESS.getCode())){
            accountId = resultVO.getResult().toString();
        }else {
            PayAccount payAccount = JSONUtils.parse2Object(resultVO.getResult().toString(), PayAccount.class);
            accountId = payAccount.getAccountId();
        }
        //对用户id进行加密
        accountId = AESUtil.encrypt(accountId, wareMap.get(accountDto.getBusinessIdType()));
        resultVO.setResult(accountId);
        return resultVO;
    }

    private boolean isValidUploadParam(AccountDto accountDto){
        if (accountDto==null|| StringUtil.isEmpty(accountDto.getBusinessIdType(), accountDto.getBusinessUserId())){
            return false;
        }
        return true;
    }

    @Override
    public ResultVO uploadPic(UserDto userDto, String idType, String channel) throws Exception {
        ResultVO resultVO = new ResultVO();

        try {
            UserPicBo userPicBo = routeManager.uploadPic(userDto, channel);

            if(thirdUserInfoService.getThirdUserInfoByUserId(userDto.getUserId())==null) {
                LOGGER.error("AccountServiceImpl uploadPic userInfo not exist userId:{}", userDto.getUserId());
                resultVO.setCode(ResultCodeEnum.PLEASE_FOLLOW_ORDER.getCode());
                resultVO.setMsg(ResultCodeEnum.PLEASE_FOLLOW_ORDER.getMsg());
                return resultVO;
            }

            ThirdUserInfo thirdUserInfo = new ThirdUserInfo();
            thirdUserInfo.setUserId(userDto.getUserId());
            thirdUserInfo.setAccountNo(userPicBo.getAccountNo());
            thirdUserInfo.setThirdType(userPicBo.getThirdType());
            thirdUserInfo.setBusinessIdType(userDto.getBusinessIdType());
            int count = thirdUserInfoService.updateThirdUserInfoByUserId(thirdUserInfo);

            if(count<1) {
                LOGGER.error("AccountServiceImpl uploadPic createThirdUserInfo error thirdUserInfo:{}", JSON.toJSON(thirdUserInfo));
                resultVO.setCode(ResultCodeEnum.SYSTEM_BUSY_ERROR.getCode());
                resultVO.setMsg(ResultCodeEnum.SYSTEM_BUSY_ERROR.getMsg());
                return resultVO;
            }

            resultVO.setResult(userPicBo);
        }
        catch(PaymentException e) {
            LOGGER.error("AccountServiceImpl uploadPic error accountId:{}, idType:{}", userDto.getUserId(), idType, e);
            resultVO.setCode(e.getErrCode());
            resultVO.setMsg(e.getErrMsg());
            return resultVO;
        }

        return resultVO;
    }

    @Override
    public ResultVO createAccount(UserDto userDto, String idType,  String createType, String channel) throws Exception {
        ResultVO resultVO = new ResultVO();
        ResultVO checkResult = isValidCreateUserParam(userDto, idType);

        if(checkResult.isFail()){
            LOGGER.warn("AccountServiceImpl createAccount param error userDto:{}, idType:{}, createType:{}, checkResult:{}",JSON.toJSON(userDto), idType, createType, JSONUtils.toJSON(checkResult));
            return checkResult;
        }

        if(userInfoService.queryUserInfoByAccountId(userDto.getUserId()) == null) {
            LOGGER.error("AccountServiceImpl createAccount userInfo not exist userId:{}", userDto.getUserId());
            resultVO.setCode(ResultCodeEnum.PLEASE_FOLLOW_ORDER.getCode());
            resultVO.setMsg(ResultCodeEnum.PLEASE_FOLLOW_ORDER.getMsg());
            return resultVO;
        }

        //先插入资料到数据库
        UserDto basicInfo = new UserDto();
        basicInfo.setName(userDto.getName());
        basicInfo.setAddress(userDto.getAddress());
        basicInfo.setIdentityInfo(userDto.getIdentityInfo());
        basicInfo.setOldBusinessUserId(userDto.getOldBusinessUserId());
        UserInfo userInfo = new UserInfo();
        userInfo.setContactInfo(AESUtil.encrypt(JSONUtils.toJSON(userDto.getContactInfos()), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
        userInfo.setAccountId(userDto.getUserId());
        userInfo.setTelNo(AESUtil.encrypt(userDto.getMobile(), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
        userInfo.setBasicInfo(AESUtil.encrypt(JSONUtils.toJSON(basicInfo), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
        userInfo.setSettleInfo(AESUtil.encrypt(JSONUtils.toJSON(userDto.getSettleAccountDto()), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
        userInfo.setShareHolderInfo(AESUtil.encrypt(JSONUtils.toJSON(userDto.getShareHolderInfo()), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
        userInfo.setBeneficiaryInfo(AESUtil.encrypt(JSONUtils.toJSON(userDto.getBeneficiaryInfo()), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
        userInfo.setOperatorInfo(AESUtil.encrypt(JSONUtils.toJSON(userDto.getOperatorInfo()), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));

        if(Constants.YOP.equals(userDto.getThirdChannelType())) {
            userInfo.setAuditStatus(AccountCreateStatusEnum.PROCESSING.getStatus());
            userInfo.setMessage(AccountCreateStatusEnum.PROCESSING.getDesc());
        }

        userInfo.setUtime(new Date());
        userInfoService.updateUserInfoByUserId(userInfo);

        try {
            SubAppBo subAppBo = null;

            if(Constants.MERCHANT.equals(createType)){
                subAppBo = routeManager.createMerchant(userDto, channel);
            }

            if(Constants.PERSONAL.equals(createType)) {
                subAppBo = routeManager.createPersonal(userDto, channel);
            }

            resultVO.setResult(subAppBo);
            return resultVO;
        }
        catch(Exception e) {
            LOGGER.error("AccountServiceImpl createUser createAccount userId:{}, idType:{}", userDto.getUserId(), idType, e);
            String errorCode = e instanceof PaymentException ? ((PaymentException) e).getErrCode() : ResultCodeEnum.DEFAULT_ERROR.getCode();
            String errorMsg = e instanceof PaymentException ? ((PaymentException) e).getErrMsg() : ResultCodeEnum.DEFAULT_ERROR.getDisplayMsg();

            if(Constants.YOP.equals(userDto.getThirdChannelType())) {
                userInfo.setAuditStatus(AccountCreateStatusEnum.FAIL.getStatus());
                userInfo.setMessage(errorMsg);
                userInfo.setUtime(new Date());
                userInfoService.updateUserInfoByUserId(userInfo);
            }

            resultVO.setCode(errorCode);
            resultVO.setMsg(errorMsg);
            return resultVO;
        }
    }

    @Override
    public ResultVO queryAccount(String businessId, String idType, String channel, String balanceAccountType) {
        ResultVO resultVO = new ResultVO();

        try {
            ThirdUserInfo thirdUserInfo = getThirdUserInfo(businessId, idType);
            QueryAccountDto queryAccountDto = new QueryAccountDto();
            queryAccountDto.setUserId(thirdUserInfo.getUserId());
            queryAccountDto.setBusinessIdType(idType);
            queryAccountDto.setThirdUserId(thirdUserInfo.getThirdUserId());
            queryAccountDto.setBalanceAccountType(balanceAccountType);
            UserBo userBo = routeManager.queryAccount(queryAccountDto);
            resultVO.setResult(userBo);
            return resultVO;
        }
        catch(PaymentException e) {
            LOGGER.error("AccountServiceImpl getUser queryUserError businessId:{}, idType:{}", businessId, idType, e);
            resultVO.setCode(e.getErrCode());
            resultVO.setMsg(e.getErrMsg());
            return resultVO;
        }
    }

    @Override
    public UserBo queryAccountByBusinessId(String businessId, String idType, String channel) throws PaymentException {
        ThirdUserInfo thirdUserInfo = getThirdUserInfo(businessId, idType);
        QueryAccountDto queryAccountDto = new QueryAccountDto();
        queryAccountDto.setUserId(thirdUserInfo.getUserId());
        queryAccountDto.setBusinessIdType(idType);
        queryAccountDto.setThirdUserId(thirdUserInfo.getThirdUserId());
        return routeManager.queryAccount(queryAccountDto);
    }

    @Override
    public String createOrUpdateThirdUserId(ThirdUserInfo thirdUserInfo, String userId, String type) throws PaymentException {
        ThirdUserInfo thirdUserInfo1 = new ThirdUserInfo();
        String thirdUserId = "";
        if (thirdUserInfo==null){
            return createThirdUserId(userId, type, "", "", "");
        }else {
            thirdUserInfo1.setUtime(new Date());
            thirdUserInfo1.setUserId(userId);
            thirdUserInfo1.setThirdUserId(thirdUserId);
            thirdUserInfo1.setThirdType(type);
            int count = thirdUserInfoService.updateThirdUserInfoByUserId(thirdUserInfo1);
            if (count<1){

            }
            return thirdUserId;
        }
    }

    @Override
    public String createThirdUserId(String userId, String type, String userType, String settleBank, String customerType) throws PaymentException {
        ThirdUserInfo thirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(userId);

        if(thirdUserInfo != null && thirdUserInfo.getThirdUserId().isEmpty()) {
            return thirdUserInfo.getThirdUserId();
        }

        if(thirdUserInfo != null && thirdUserInfo.getThirdUserId().equals(thirdUserInfo.getUserId())) {
            if(!thirdUserInfo.getThirdType().equals(type)) {
                thirdUserInfoService.deleteByPrimaryKey(thirdUserInfo.getId());
                thirdUserInfo = null;
            }
            else {
                return thirdUserInfo.getThirdUserId();
            }
        }

        if(thirdUserInfo != null && !thirdUserInfo.getThirdUserId().isEmpty()) {
            if(Constants.YOP.equals(thirdUserInfo.getThirdType())) {
                UserInfo userInfo = userInfoService.queryUserInfoByAccountId(thirdUserInfo.getUserId());

                if(AccountCreateStatusEnum.canSubmit(userInfo.getAuditStatus())) {
                    return thirdUserInfo.getThirdUserId();
                }
            }
            // 若为买家，则继续后续流程更新数据库数据，若为商家，则直接抛出异常不进行后续处理
            if (Constants.PINGAN.equals(thirdUserInfo.getThirdType()) && StringUtils.isNotBlank(customerType) && CustomerTypeEnum.BUYER.getType().equals(customerType)) {
                return thirdUserInfo.getThirdUserId();
            }
            throw new PaymentException(ResultCodeEnum.ACCOUNT_IS_EXIST);
        }

        ThirdUserInfo thirdUserInfo1 = new ThirdUserInfo();
        thirdUserInfo1.setUserId(userId);
        thirdUserInfo1.setThirdType(type);
        thirdUserInfo1.setCtime(new Date());
        thirdUserInfo1.setUtime(new Date());
        thirdUserInfo1.setThirdUserId(userId);
        thirdUserInfo1.setUserType(userType);
        thirdUserInfo1.setSettleBank(settleBank);
        int count = thirdUserInfoService.createThirdUserInfo(thirdUserInfo1);

        if(count<1) {
            LOGGER.error("AccountServiceImpl#createThirdUserId create failed userId:{} type:{}", userId, type);
        }

        return StringUtils.EMPTY;
    }

    @Override
    public String getThirdUserIdByUserId(String userId, String channel) throws PaymentException {
        //获取第三方userId
        ThirdUserInfo thirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(userId);
        if (thirdUserInfo==null||thirdUserInfo.getThirdUserId()==null){
            throw new PaymentException(ResultCodeEnum.THIRD_USER_ID_NOT_EXIST);
        }
        return thirdUserInfo.getThirdUserId();
    }


    private String getUserId(String businessId, String idType) throws PaymentException {
        String userId = payAccountService.getAccountIdByBusiness(idType, businessId);

        if(userId==null) {
            LOGGER.warn("AccountServiceImpl getUser userId not found businessId:{}, idType:{}", businessId, idType);
            throw new PaymentException(ResultCodeEnum.USER_NOT_FOUND);
        }

        return userId;
    }


    private ThirdUserInfo getThirdUserInfo(String businessId, String idType) throws PaymentException {
        String userId = payAccountService.getAccountIdByBusiness(idType, businessId);

        if(userId==null) {
            LOGGER.warn("AccountServiceImpl getUser userId not found businessId:{}, idType:{}", businessId, idType);
            throw new PaymentException(ResultCodeEnum.USER_NOT_FOUND);
        }

        //获取第三方userId
        ThirdUserInfo thirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(userId);

        if(thirdUserInfo == null || thirdUserInfo.getThirdUserId() == null) {
            throw new PaymentException(ResultCodeEnum.THIRD_USER_ID_NOT_EXIST);
        }

        return thirdUserInfo;
    }


    @Override
    public ResultVO uploadImg(MultipartFile[] multipartFiles, List<String> type, String accountId) throws Exception {
        ResultVO resultVO = new ResultVO();
        try{
            Map<String, String> picMap = new HashMap<>();
            // 上传图片到fastdfs
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost uploadFile = new HttpPost(fileUploadUrl);
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            for(int i=0;i<multipartFiles.length;i++) {
                // 把文件加到HTTP的post请求中
                builder.addBinaryBody("file", multipartFiles[i].getInputStream(), ContentType.APPLICATION_OCTET_STREAM,
                        multipartFiles[i].getOriginalFilename()
                );
                uploadFile.setEntity(builder.build());
                CloseableHttpResponse response = httpClient.execute(uploadFile);
                HttpEntity responseEntity = response.getEntity();
                String responseStr = EntityUtils.toString(responseEntity, "UTF-8");
                LOGGER.info("AccountServiceImpl#uploadImg upload file response:{}", responseStr);
                Map<String, String> stringStringMap = JSONUtils.parse2Map(responseStr, String.class, String.class);
                if(!"0".equals(stringStringMap.get("code"))){
                    return ResultVO.createError(ResultCodeEnum.PIC_UPLOAD_ERROR);
                }
                picMap.put(type.get(i),stringStringMap.get("result"));
            }

            //图片入库
            UserInfoPicChange(accountId, picMap);
            resultVO.setResult(picMap);
            return resultVO;
        }catch (Exception e){
            LOGGER.error("AccountServiceImpl#uploadImg error. e:{}", e);
            throw e;
        }
    }

    @Override
    public boolean isValidPersonalEnumParam(PersonalAccountVo personalAccountVo){
        try{
            AccountChannelEnum.valueOf(personalAccountVo.getAccountChannel());
            ProfessionEnum.valueOf(personalAccountVo.getProfession());
            BusinessIdTypeEnum.valueOf(personalAccountVo.getBusinessIdType());
            GenderEnum.valueOf(personalAccountVo.getGenderEnum());
            BankCardEnum.valueOf(personalAccountVo.getCardType());
            CertTypeEnum.valueOf(personalAccountVo.getCertType());
            return true;
        }catch (Exception e){
            LOGGER.warn("AccountController isValidPersonalEnumParam enum error AccountChannelEnum:{}, ProfessionEnum:{}, BusinessIdTypeEnum:{}, " +
                            "GenderEnum:{}, BankCardEnum:{}", personalAccountVo.getAccountChannel(), personalAccountVo.getProfession(), personalAccountVo.getBusinessIdType(),
                    personalAccountVo.getGenderEnum(), personalAccountVo.getCardType(), e);
            return false;
        }
    }

    @Override
    public boolean isValidMerchantEnumParam(MerchantAccountVo merchantAccountVo){
        return isValidMerchantEnumParam(merchantAccountVo.getBusinessIdType(), merchantAccountVo.getAccountChannel(), merchantAccountVo.getIndustry(), merchantAccountVo.getCardType());

    }

    private boolean isValidMerchantEnumParam(String businessIdType, String accountChannel, String industry, String cardType) {
        try{
            AccountChannelEnum.valueOf(accountChannel);
            IndustryEnum.valueOf(industry);
            BankCardEnum.valueOf(cardType);
            return true;
        }catch (Exception e){
            LOGGER.warn("AccountController isValidPersonalEnumParam enum error AccountChannelEnum:{}, IndustryEnum:{}, BusinessIdTypeEnum:{}, " +
                            "BankCardEnum:{}", accountChannel, industry, businessIdType,
                    cardType, e);
            return false;
        }
    }

    @Override
    public void UserInfoPicChange(String accountId, Map<String, String> picMap) throws Exception {
        UserInfo userInfo = userInfoService.queryUserInfoByAccountId(accountId);

        if(userInfo==null) {
            userInfo = new UserInfo();
            userInfo.setAccountId(accountId);
            String picJson = JSONUtils.toJSON(picMap);
            userInfo.setPicInfo(AESUtil.encrypt(picJson, ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
            userInfo.setCtime(new Date());
            //todo 设计一下怎么动态改
            userInfo.setVersion(0);
            userInfoService.createUserInfo(userInfo);
        }
        else {
            UserInfo userInfo1 = new UserInfo();
            String picInfo = userInfo.getPicInfo();
            Map<String, String> oldPicMap = JSONUtils.parse2Map(AESUtil.decrypt(picInfo, ApolloUtil.getProperty(Constants.USER_INFO_KEY)), String.class, String.class);
            oldPicMap.putAll(picMap);
            userInfo1.setUtime(new Date());
            userInfo1.setAccountId(accountId);
            userInfo1.setPicInfo(AESUtil.encrypt(JSONUtils.toJSON(oldPicMap), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
            userInfoService.updateUserInfoByUserId(userInfo1);
        }
    }

    @Override
    public void sendActiveCodeByPhoneNum(ActiveCodeDto activeCodeDto) throws PaymentException {
        String accountId = "";
        AccountDto accountDto = new AccountDto();
        accountDto.setBusinessIdType(activeCodeDto.getBusinessIdType());
        accountDto.setBusinessUserId(activeCodeDto.getBusinessUserId());
        ResultVO accountResult = createAccount(accountDto);

        if(!accountResult.getCode().equals(ResultCodeEnum.SUCCESS.getCode())){
            accountId = accountResult.getResult().toString();
        }
        else {
            PayAccount payAccount = JSONUtils.parse2Object(accountResult.getResult().toString(), PayAccount.class);
            accountId = payAccount.getAccountId();
        }

        activeCodeDto.setAccountId(accountId);
        routeManager.sendActiveCodeByPhoneNum(activeCodeDto);
    }

    @Override
    public void personalSettleCardReBind(PersonalCardBindDto personalCardBindDto) throws PaymentException {
        String userId = getUserId(personalCardBindDto.getBusinessUserId(), personalCardBindDto.getBusinessIdType());
        personalCardBindDto.setUserId(userId);
        UserInfo userInfo = userInfoService.queryUserInfoByAccountId(userId);
        //取出结算账户信息
        SettleAccountDto settleAccountDto = null;
        UserDto userDto = null;
        try {
            String jsonSettleAccount = AESUtil.decrypt(userInfo.getSettleInfo(), ApolloUtil.getProperty(Constants.USER_INFO_KEY));
            settleAccountDto = JSONUtils.parse2Object(jsonSettleAccount, SettleAccountDto.class);
            String jsonUserDto = AESUtil.decrypt(userInfo.getBasicInfo(), ApolloUtil.getProperty(Constants.USER_INFO_KEY));
            userDto= JSONUtils.parse2Object(jsonUserDto, UserDto.class);
        } catch (Exception e) {
            LOGGER.error("FuminAdapter#withdraw userInfo decrypt error userId:{}", userId, e);
        }
        if (settleAccountDto == null || userDto == null) {
            throw new PaymentException(ResultCodeEnum.THIRD_USER_ID_NOT_EXIST, "用户信息取出失败");
        }

        if(personalCardBindDto.getAccount().equals(settleAccountDto.getRecipient().getAccount())){
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR, "卡号不能和换绑前卡号相同");
        }

        if(!personalCardBindDto.getName().equals(settleAccountDto.getRecipient().getName())){
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR, "换绑卡户名要和开户名一致");
        }

        routeManager.personalCardBind(personalCardBindDto);
        Recipient recipient = settleAccountDto.getRecipient();
        UnBindCardDto unBindCardDto = new UnBindCardDto();
        unBindCardDto.setAccount(recipient.getAccount());
        unBindCardDto.setAccountName(recipient.getName());
        unBindCardDto.setMobile(recipient.getMobile());
        unBindCardDto.setUserId(userId);
        unBindCardDto.setAccountType(Constants.PERSONAL);
        unBindCardDto.setCardId(userDto.getIdentityInfo().getId());
        unBindCardDto.setBusinessIdType(personalCardBindDto.getBusinessIdType());
        recipient.setAccount(personalCardBindDto.getAccount());
        recipient.setMobile(personalCardBindDto.getMobile());
        recipient.setOpenBank(personalCardBindDto.getOpenBank());
        recipient.setOpenBankCode(personalCardBindDto.getOpenBankCode());
        recipient.setSubBank(personalCardBindDto.getBranchBankName());
        recipient.setSubBankCode(personalCardBindDto.getBranchBankCd());
        recipient.setName(personalCardBindDto.getName());
        settleAccountDto.setRecipient(recipient);
        userInfo.setUtime(new Date());
        try {
            userInfo.setSettleInfo(AESUtil.encrypt(JSONUtils.toJSON(settleAccountDto), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
        } catch (Exception e) {
            LOGGER.error("AccountServiceImpl#personalSettleCardReBind error personalCardBindDto:{}", JSON.toJSONString(personalCardBindDto), e);
            throw new PaymentException(ResultCodeEnum.DEFAULT_ERROR);
        }
        userInfoService.updateUserInfoByUserId(userInfo);
        ThirdUserInfo thirdUserInfo = getThirdUserInfo(personalCardBindDto.getBusinessUserId(), personalCardBindDto.getBusinessIdType());
        thirdUserInfo.setSettleBank(personalCardBindDto.getOpenBank());
        thirdUserInfo.setUtime(new Date());
        thirdUserInfoService.updateThirdUserInfoByUserId(thirdUserInfo);
        try {
            routeManager.unBindCard(unBindCardDto);
        } catch (Exception e) {
            LOGGER.error("AccountServiceImpl#personalSettleCardReBind unBindCard error unBindCardDto:{}", JSON.toJSONString(unBindCardDto), e);
        }
    }


    @Override
    public Integer merchantSettleCardReBind(MerchantCardBindDto merchantCardBindDto) throws PaymentException {
        LOGGER.info("AccountServiceImpl#merchantSettleCardReBind param:{}", JSONUtils.toJSON(merchantCardBindDto));
        // 校验参数 - 填充参数
        ResultVO checkResult = checkMerchantCardBindParam(merchantCardBindDto);

        if(checkResult.isFail()) {
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR, checkResult.getMsg());
        }

        UserInfo userInfo = userInfoService.queryUserInfoByAccountId(merchantCardBindDto.getUserId());
        // 取出结算账户信息
        SettleAccountDto settleAccountDto = null;

        try {
            String jsonSettleAccount = AESUtil.decrypt(userInfo.getSettleInfo(), ApolloUtil.getProperty(Constants.USER_INFO_KEY));
            settleAccountDto = JSONUtils.parse2Object(jsonSettleAccount, SettleAccountDto.class);
        } catch(Exception e) {
            LOGGER.error("FuminAdapter#withdraw userInfo decrypt error userId:{}", merchantCardBindDto.getUserId(), e);
        }

        if(settleAccountDto == null) {
            throw new PaymentException(ResultCodeEnum.THIRD_USER_ID_NOT_EXIST, "用户信息取出失败");
        }

        if(!merchantCardBindDto.getSettleName().equals(settleAccountDto.getRecipient().getName())) {
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR, "换绑卡户名要和开户名一致");
        }

        ThirdUserInfo thirdUserInfo = getThirdUserInfo(merchantCardBindDto.getBusinessUserId(), merchantCardBindDto.getBusinessIdType());

        // 平安兼容逻辑
        if(Constants.PINGAN.equals(thirdUserInfo.getThirdType())) {
            //校验下该卡是否绑过
            boolean isBinded = applyBankcardService.isBinded(merchantCardBindDto.getUserId(), merchantCardBindDto.getAccount());
            if (isBinded) {
                LOGGER.info("merchantSettleCardReBind 卡已绑定 开始走解绑逻辑:UserId:{},accout:{}",merchantCardBindDto.getUserId(),merchantCardBindDto.getAccount());
                UnBindCardDto unBindCardDto = new UnBindCardDto();
                unBindCardDto.setAccount(merchantCardBindDto.getAccount());
                unBindCardDto.setAccountName(merchantCardBindDto.getSettleName());
                unBindCardDto.setMobile(merchantCardBindDto.getMobile());
                unBindCardDto.setUserId(merchantCardBindDto.getUserId());
                unBindCardDto.setAccountType(Constants.MERCHANT);
                unBindCardDto.setBusinessIdType(merchantCardBindDto.getBusinessIdType());
                routeManager.unBindCard(unBindCardDto);
            }

            ApplyBankcardModifyDto modifyDto = ApplyBankcardModifyDto.builder().
                    resendCode(merchantCardBindDto.getResendCode()).
                    businessIdType(BusinessIdTypeEnum.type(merchantCardBindDto.getBusinessIdType())).
                    businessId(merchantCardBindDto.getBusinessUserId()).
                    accountId(merchantCardBindDto.getUserId()).
                    businessOrderNo(merchantCardBindDto.getBusinessOrderNo()).
                    callback(merchantCardBindDto.getCallback()).
                    source(Constants.SOURCE_MODIFY_BANKCARD).
                    corporationName(merchantCardBindDto.getCorporationName()).corporationIdNo(merchantCardBindDto.getCorporationIdNo()).corporationPhone(merchantCardBindDto.getCorporationPhone()).
                    contactName(merchantCardBindDto.getContactName()).contactIdCard(merchantCardBindDto.getContactIdCard()).contactPhone(merchantCardBindDto.getContactPhone()).
                    accountName(merchantCardBindDto.getSettleName()).acct(merchantCardBindDto.getAccount()).bankCd(merchantCardBindDto.getOpenBankCode()).bankName(merchantCardBindDto.getOpenBank()).branchBankCd(merchantCardBindDto.getBranchBankCd()).branchBankName(merchantCardBindDto.getBranchBankName()).mobileNo(merchantCardBindDto.getMobile()).
                    build();
            return applyBankcardService.apply(modifyDto, false);
        }
        // 平安切富民完成后可去掉
        else {
            routeManager.merchantCardBind(merchantCardBindDto);
            Recipient recipient = settleAccountDto.getRecipient();
            UnBindCardDto unBindCardDto = new UnBindCardDto();
            unBindCardDto.setAccount(recipient.getAccount());
            unBindCardDto.setAccountName(recipient.getName());
            unBindCardDto.setMobile(recipient.getMobile());
            unBindCardDto.setUserId(merchantCardBindDto.getUserId());
            unBindCardDto.setAccountType(Constants.MERCHANT);
            unBindCardDto.setBusinessIdType(merchantCardBindDto.getBusinessIdType());
            recipient.setAccount(merchantCardBindDto.getAccount());
            recipient.setMobile(merchantCardBindDto.getMobile());
            recipient.setOpenBank(merchantCardBindDto.getOpenBank());
            recipient.setOpenBankCode(merchantCardBindDto.getOpenBankCode());
            recipient.setName(merchantCardBindDto.getSettleName());
            recipient.setSubBank(merchantCardBindDto.getBranchBankName());
            recipient.setSubBankCode(merchantCardBindDto.getBranchBankCd());
            settleAccountDto.setRecipient(recipient);
            userInfo.setUtime(new Date());

            try {
                userInfo.setSettleInfo(AESUtil.encrypt(JSONUtils.toJSON(settleAccountDto), ApolloUtil.getProperty(Constants.USER_INFO_KEY)));
            }
            catch(Exception e) {
                LOGGER.error("AccountServiceImpl#merchantSettleCardReBind error merchantCardBindDto:{}", JSON.toJSONString(merchantCardBindDto), e);
                throw new PaymentException(ResultCodeEnum.DEFAULT_ERROR);
            }

            userInfoService.updateUserInfoByUserId(userInfo);

            thirdUserInfo.setSettleBank(merchantCardBindDto.getOpenBank());
            thirdUserInfo.setUtime(new Date());
            thirdUserInfoService.updateThirdUserInfoByUserId(thirdUserInfo);

            try {
                routeManager.unBindCard(unBindCardDto);
            }
            catch(Exception e) {
                LOGGER.error("AccountServiceImpl#personalSettleCardReBind unBindCard error unBindCardDto:{}", JSON.toJSONString(unBindCardDto), e);
            }

            return ApplyBankcardStatusEnum.AUDITING.getStatus();
        }
    }

    private ResultVO checkMerchantCardBindParam(MerchantCardBindDto merchantCardBindDto) {
        // 填充支付平台商户信息
        String userId = payAccountService.getAccountIdByBusiness(merchantCardBindDto.getBusinessIdType(), merchantCardBindDto.getBusinessUserId());

        if(StringUtils.isBlank(userId)) {
            return ResultVO.createError(ResultCodeEnum.USER_NOT_FOUND);
        }

        merchantCardBindDto.setUserId(userId);

        ThirdUserInfo thirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(userId);

        if(Constants.PINGAN.equals(thirdUserInfo.getThirdType())) {
            return ResultVO.createSuccess();
        }

        // 填充银行信息
        String openBankCode = merchantCardBindDto.getOpenBankCode();

        if(StringUtils.isBlank(merchantCardBindDto.getOpenBankCode())) {
            openBankCode = fmBankCodeService.queryCodeByName(merchantCardBindDto.getOpenBank());

            if(StringUtils.isBlank(openBankCode)) {
                return ResultVO.createError(ResultCodeEnum.OPEN_BANK_ERROR);
            }

            merchantCardBindDto.setOpenBankCode(openBankCode);
        }

        // 填充支行信息
        if(StringUtils.isBlank(merchantCardBindDto.getBranchBankName())) {
            SubBankCode subBank = StringUtils.isBlank(merchantCardBindDto.getBranchBankCd()) ? null : subBankCodeService.queryByCode(merchantCardBindDto.getBranchBankCd());

            // 简称默认 支行必不能为空
            if(FmBankCode.BASE_BANK_SHORT_NAME.equals(openBankCode) && null == subBank) {
                return ResultVO.createError(ResultCodeEnum.SUB_BANK_ERROR);
            }

            if(null != subBank) {
                // 兼容荷叶
                merchantCardBindDto.setBranchBankName(subBank.getName());
            }
        }

        return ResultVO.createSuccess();
    }

    private ResultVO isValidCreateUserParam(UserDto userDto, String idType){
        if(userDto==null || StringUtil.isEmpty(idType)) {
            return ResultVO.createError(ResultCodeEnum.PARAM_ERROR);
        }

        if(StringUtil.isEmpty(userDto.getName()) || userDto.getName().length()>32) {
            return ResultVO.createError(ResultCodeEnum.PARAM_ERROR.getCode(), "公司名称为空 或者 长度大于32个字符");
        }

        if(userDto.getIdentityInfo()==null || StringUtil.isEmpty(userDto.getIdentityInfo().getId())) {
            return ResultVO.createError(ResultCodeEnum.PARAM_ERROR.getCode(),"证件信息为空");
        }

        if(StringUtil.isEmpty(userDto.getMobile()) || !MatcherUtil.isValidPhoneNo(userDto.getMobile())) {
            return ResultVO.createError(ResultCodeEnum.PARAM_ERROR.getCode(),"手机号格式错误");
        }

        //如果地址不为空 那么长度不可以多余256
        if(userDto.getAddress() != null && userDto.getAddress().length() > 256) {
            return ResultVO.createError(ResultCodeEnum.PARAM_ERROR.getCode(),"地址不为空,长度不可以多余256字符");
        }

        return ResultVO.createSuccess();
    }
}
